frequency_over_messages = {
    /@qq\.com$/i => /frequency limited/i,
    /@163\.com$/i => /(?:MI\:SFQ|RP\:QRC)/i,
    /@126\.com$/i => /(?:MI\:SFQ|RP\:QRC)/i
}

user_not_found_message = /x\-postfix\:|User (is )?not found|User unknown|No such user|Invalid User|Not? exist|Mailbox not found|User suspended|invalid address|doesn\'t have .*account|mailbox unavailable|user not local|bad address|couldn\'t find|bad host domain|unreachable/i

pid_file = 'tmp/pids/mailman.pid'

namespace :bouncer do
  desc 'Tasks related to mail delivery and bounce handling.'

  task start: :environment do
    desc 'Handles bounces'
    handle_bounces(frequency_over_messages, user_not_found_message)
  end

  task stop: :environment do
    desc 'Stops bounce handling'
    Process.kill(:TERM, File.read(pid_file).to_i) rescue nil
  end
end

def handle_bounces(frequency_over_messages, user_not_found_message)
  pid = fork do
    Mailman::Application.run do
      File.open(pid_file, 'w') do |f|
        f.write pid
      end
      redis = Redis.new(REDIS_CONF)
      subject /undelivered mail returned to sender/i do
        begin
          Mailman.logger.info "Bounce Received."
          bounce = BounceEmail::Mail.new(message)
          to = bounce.original_mail.to[0];
          mail_id = bounce.original_mail.header['X-MAIL-ID']
          Mailman.logger.info "Recipient: #{to}"
          Mailman.logger.info "reason: #{bounce.reason}"
          unless mail_id
            Mailman.logger.warn 'No mail id. Ignored.'
            next
          end
          Mailman.logger.info "find: #{mail_id}"

          user = User.find_by(email: to)
          Bounce.create( user: user,
            promotion_mail_id: mail_id,
                       reason: bounce.reason,
                         code: bounce.code,
                  domain_name: email.split('@').last)

          frequency_over_messages.each do |domain, characteristics|
            if to =~ domain and bounce.body =~ characteristics
              redis.publish :hang, to.split('@').last.strip.downcase
              break
            end
          end

          if bounce.reason =~ user_not_found_message
            InvalidUser.find_or_create_by(user: user)
          end
        rescue => e
          Mailman.logger.error e.message
          sleep 30.seconds
          retry
        end
      end
    end
  end
  Process.detach pid
end

